package com.db.javaschool.ionio;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.zip.GZIPInputStream;

import static com.db.javaschool.ionio.Utils.format;
import static com.db.javaschool.ionio.Utils.port;

public class NetCopyIOServer {

    public static void main(String... args) {

        System.out.println("Server start: " + format.format(new Date()));

        int size = 1024 * 1024 * 100 + 1028 * 100;

        byte[] buf = new byte[size];

        try (ServerSocket serverSocket = new ServerSocket(port)) {

            while (true) {

                System.out.println("Accept");

                try (Socket socket = serverSocket.accept()) {

                    System.out.println("Start: " + format.format(new Date()));

                    try (BufferedInputStream input = new BufferedInputStream(socket.getInputStream(), size);
                         BufferedOutputStream output = new BufferedOutputStream(socket.getOutputStream(), size);
                         BufferedOutputStream fileOutput =
                                 new BufferedOutputStream(new FileOutputStream(new File("copy.io.net.bin")), size)) {

                        try (ObjectInputStream objectInputStream = new ObjectInputStream(input)) {

                            System.out.println("Object streams: " + format.format(new Date()));

                            long fileSize;

                            fileSize = objectInputStream.readLong();

                            System.out.println("Content size: " + fileSize);

                            long readSize = 0;

                            int i;

                            byte[] content;

                            try (ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream((int) fileSize)) {

                                while ((readSize < fileSize) && ((i = input.read(buf, 0, size)) != -1)) {

                                    System.out.println("Read: " + i);

                                    arrayOutputStream.write(buf, 0, i);

                                    readSize += i;

                                    System.out.println("Stored: " + readSize);
                                }

                                arrayOutputStream.flush();

                                content = arrayOutputStream.toByteArray();

                                System.out.println("Content length: " + content.length);


                                try (GZIPInputStream gzipInputStream =
                                                new GZIPInputStream(new ByteArrayInputStream(content))) {

                                    readSize = 0;

                                    while (((i = gzipInputStream.read(buf, 0, size)) != -1)) {

                                        System.out.println("Read 2: " + i);

                                        fileOutput.write(buf, 0, i);

                                        readSize += i;

                                        System.out.println("Stored 2: " + readSize);
                                    }

                                    System.out.println("ReadSize: " + readSize + ", i: " + i);

                                    System.out.println("File is flushing: " + format.format(new Date()));

                                    fileOutput.flush();

                                    System.out.println("File is stored: " + format.format(new Date()));

                                    try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(output)) {
                                        objectOutputStream.writeUTF("Upload is finished");
                                    }
                                }
                            }
                        }
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("End: " + format.format(new Date()));
    }
}
